﻿using System;
using System.Windows.Navigation;
using System.Windows.Controls;

using PasswordProvider.ViewModel;
using PasswordProvider.ViewModel.Framework;
using PasswordProvider.ObjectModel;

namespace PasswordProvider.ViewModel.Service
{
    /// <summary>
    /// Provides navigation services for the application. Encapsulates rules for navigation between pages.
    /// </summary>
    public static class NavigationManager
    {
        /// <summary>
        /// Event is raised when navigation to a new page is complete.
        /// </summary>
        public static event EventHandler Navigated;

        #region Fields, Construction
        
        private static NavigationService _navigationService;
        private static object NextView { get; set; }
        
        // Static constructor
        static NavigationManager()
        {
            SecurityManager.AuthenticationInvalidatedByTimer += delegate { GoToEnterPasswordView(); };
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Set the navigation service used by the NavigationManager
        /// </summary>
        public static void SetNavigationService(NavigationService service)
        {
             _navigationService = service;
             _navigationService.Navigated += new NavigatedEventHandler(NavigationService_Navigated);
             _navigationService.Navigating += new NavigatingCancelEventHandler(NavigationService_NavigationBegun);                    
        }
        
        /// <summary>
        /// Get the current view model which is serving as the data context of the current page.
        /// </summary>
        internal static object CurrentView
        {
            get;
            private set;
        }
        
        #endregion // public properteis

        #region Public Methods

        /// <summary>
        /// Navigate directly to the enter password view
        /// </summary>
        public static object GoToEnterPasswordView()
        {
            return NavigateTo(new EnterPasswordViewModel(false));
        }
        /// <summary>
        /// Navigate directly to the enter password view. When password is entered, view model will
        /// call ProtectedSiteCollection.Open to open the file at the specified path.
        /// </summary>
        public static object GoToEnterPasswordView(string openFilePath)
        {
            return NavigateTo(new EnterPasswordViewModel(openFilePath));
        }
        /// <summary>
        /// Navigate to the Welcome Page
        /// </summary>
        public static object GoToWelcomePage()
        {
            // Go to the welcome page.
            return NavigateTo(new WelcomeViewModel());
        }

        #endregion

        #region Internal Methods

        /// <summary>
        /// Navigate directly to the options view
        /// </summary>
        internal static object GoToOptionsView()
        {
            Type[] types = new Type[]
            {
                typeof(ViewOptionsViewModel),
                typeof(SecurityOptionsViewModel),
                typeof(BrowserOptionsViewModel)
            };

            return NavigateTo(new SequentialPageViewerViewModel(types));
        }

        /// <summary>
        /// Navigate directly to the manage view
        /// </summary>
        internal static object GoToManageView()
        {
            Type[] types = new Type[]
            {
                typeof(FileActionsViewModel),
                typeof(SetPasswordViewModel)                
            };

            return NavigateTo(new SequentialPageViewerViewModel(types));
        }        
       
        /// <summary>
        /// Navigate to the Set Password page, passing along a path to use as 
        /// the location for a new data file which will recieve the new password.
        /// </summary>
        internal static object GoToSetPasswordView(string newFilePath)
        {
            return NavigateTo(new SetPasswordViewModel(newFilePath));
        }


        /// <summary>
        /// callback is a delegate (Predicate) that
        /// takes a ProtectedString as the password and returns true or false to indicate 
        /// whether the password validation attempt was successful.
        /// </summary>
        internal static object GoToEnterPasswordView(bool showAttentionGetter, Predicate<ProtectedString> onPasswordEnteredCallback)
        {
            return NavigateTo(new EnterPasswordViewModel(showAttentionGetter, onPasswordEnteredCallback));
        } 
        
        /// <summary>
        /// Navigate directly to the sites list view
        /// </summary>
        internal static object GoToSitesListView()
        {
            return NavigateTo(_sitesListVM);
        }  
        // Cashe the sites list view model - no reason to recreate it 
        // when navigating away to a property page or options page.
        private static SitesListViewModel _sitesListVM = new SitesListViewModel();
        
        /// <summary>
        /// Navigate directly to the login site details view.
        /// </summary>
        internal static object GoToSiteDetailsView(LogOnSite site, bool isNewSite)
        {
            return NavigateTo(new LogOnSiteDetailsViewModel(site, isNewSite));
        }
        
        /// <summary>
        /// Navigate directly to the credit card site details view.
        /// </summary>
        internal static object GoToSiteDetailsView(CreditCardSite site, bool isNewSite)
        {
            return NavigateTo(new CreditCardDetailsViewModel(site, isNewSite));
        }

        /// <summary>
        /// Navigate directly to the credit card site details view.
        /// </summary>
        internal static object GoToSiteDetailsView(GenericSite site, bool isNewSite)
        {
            return NavigateTo(new GenericSiteDetailsViewModel(site, isNewSite));
        }

        #endregion // public methods

        #region Private Helpers

        private static void HandleViewModelCompletedTask(object sender, EventArgs e)
        {
            // Remove the event handler.
            IRequestClose vm = sender as IRequestClose;
            vm.CloseRequested -= new EventHandler(HandleViewModelCompletedTask);

            if (NextView != null)
            {
                _navigationService.Navigate(NextView);
                NextView = null;             
            }
            else
            {
                GoToSitesListView();
            }              
        }

        static void NavigationService_NavigationBegun(object sender, NavigatingCancelEventArgs e)
        {
            IRequestClose content = e.Content as IRequestClose;

            if (content is SiteDetailsViewModel || content is SequentialPageViewerViewModel)
            {
                if (PasswordProviderData.Current != null && !PasswordProviderData.Current.SecurityManager.IsAuthenticated)
                {
                    GoToEnterPasswordView(true,
                        (password) =>
                        {
                            bool success = PasswordProviderData.Current.SecurityManager.Authenticate(password);
                            if (success)
                            {
                                NextView = content;
                            }
                            return success;
                        });
                    e.Cancel = true;
                }
            }
        }


        static void NavigationService_Navigated(object sender, NavigationEventArgs e)
        {
            if (CurrentView is WelcomeViewModel || CurrentView is EnterPasswordViewModel)
                _navigationService.RemoveBackEntry();

            CurrentView = _navigationService.Content as VisualViewModel;

            if (Navigated != null)
                Navigated(sender, e);

            if (_navigationService.CanGoBack)
                _navigationService.RemoveBackEntry(); // allow objects in journal to be collected.
        }
        
        private static object NavigateTo(object target)
        {
            _navigationService.Navigate(target);

            IRequestClose closer = target as IRequestClose;
            if (closer != null)
            {
                closer.CloseRequested += new EventHandler(HandleViewModelCompletedTask);
            }

            return target;
        }

        #endregion // Private Helpers


    }
}
